﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

using LowLevelGraphics.ColorSpaces;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public class ExperimentalSkinDetection : BaseImageFilter
    {
        protected bool m_bNormalize = true;

        /// <summary>
        /// Initializes a new instance of the <see cref="ExperimentalSkinDetection"/> class.
        /// </summary>
        public ExperimentalSkinDetection()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ExperimentalSkinDetection"/> class.
        /// </summary>
        /// <param name="_experimentalSkinDetection">The _experimental skin detection.</param>
        internal ExperimentalSkinDetection(ExperimentalSkinDetection _experimentalSkinDetection)
        {
            m_bNormalize = _experimentalSkinDetection.m_bNormalize;
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="ExperimentalSkinDetection"/> is normalize.
        /// </summary>
        /// <value><c>true</c> if normalize; otherwise, <c>false</c>.</value>
        public bool Normalize
        {
            get { return m_bNormalize; }
            set { m_bNormalize = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nHeight = _bitmap.Height;
            int nWidth = _bitmap.Width;
            Color color = Color.Transparent;
            int x =0;
            int y = 0;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    color = _bitmap.GetPixel(x, y);
                    int nR = color.R;
                    int nG = color.G;
                    int nB = color.B;
                    int nSum = nR + nG + nB;
                    if (m_bNormalize)
                    {
                        nR = (int)((float)nR / nSum * 255);
                        nG = (int)((float)nG / nSum * 255);
                        nB = (int)((float)nB / nSum * 255);
                    }

                    bool bIsSkin = ExtractRGB(_bitmap, color);
                    //RGB Mode detection used with ExtractRGB function
                    //_bitmap.SetPixel(x, y, ExtractRGB(_bitmap, color, x, y) ? Definitions.White : Definitions.Black);
                    //bool bIsSkin = color.R > color.B && color.B > color.G && Math.Abs(color.G-color.B)<11;
                    _bitmap.SetPixel(x, y, bIsSkin ? Definitions.White : Definitions.Black);
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// Extracts the RGB.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="color">The color.</param>
        /// <returns></returns>
        private bool ExtractRGB(UnsafeBitmap _bitmap, Color color)
        {
            int nR = color.R;
            int nG = color.G;
            int nB = color.B;
            bool bIsSkin = (nR > 95 && nG > 40 && nB > 20
                && Math.Max(nR, Math.Max(nG, nB)) - Math.Min(nR, Math.Min(nG, nB)) > 15
                && Math.Abs(nR - nG) > 15 && nR > nG && nR > nB
                );
            return bIsSkin;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ExperimentalSkinDetection(this);
        }
    }
}
